package simple;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.MessageDigest;

@Slf4j
public class AlgorithmUtils {

    public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

    /**
     * AES加密
     *
     * @param dataArr      待加密数据
     * @param keyArr       密钥
     * @param algorithm    加密算法/工作模式/填充方式
     * @param keyAlgorithm key算法
     * @return byte[]   加密数据
     * @throws Exception
     */
    public static byte[] aesEncrypt(byte[] dataArr, byte[] keyArr,
                                    String algorithm, String keyAlgorithm) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithm);
        SecretKeySpec key = new SecretKeySpec(keyArr, keyAlgorithm);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(dataArr);
    }

    /**
     * AES加密
     *
     * @param dataArr      待加密数据
     * @param keyArr       密钥
     * @param algorithm    加密算法/工作模式/填充方式
     * @param keyAlgorithm key算法
     * @param ivArr        偏移量
     * @return byte[]   加密数据
     * @throws Exception
     */
    public static byte[] aesEncrypt(byte[] dataArr, byte[] keyArr,
                                    String algorithm, String keyAlgorithm,
                                    byte[] ivArr) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithm);
        SecretKeySpec key = new SecretKeySpec(keyArr, keyAlgorithm);
        IvParameterSpec iv = new IvParameterSpec(ivArr);
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        return cipher.doFinal(dataArr);
    }

    /**
     * AES解密
     *
     * @param dataArr      待解密数据
     * @param keyArr       密钥
     * @param algorithm    加密算法/工作模式/填充方式
     * @param keyAlgorithm key算法
     * @return byte[]   解密数据
     * @throws Exception
     */
    public static byte[] aesDecrypt(byte[] dataArr, byte[] keyArr,
                                    String algorithm, String keyAlgorithm) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithm);
        SecretKeySpec key = new SecretKeySpec(keyArr, keyAlgorithm);
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(dataArr);
    }

    /**
     * AES解密
     *
     * @param dataArr      待解密数据
     * @param keyArr       密钥
     * @param algorithm    加密算法/工作模式/填充方式
     * @param keyAlgorithm key算法
     * @param ivArr        偏移量
     * @return byte[]   解密数据
     * @throws Exception
     */
    public static byte[] aesDecrypt(byte[] dataArr, byte[] keyArr,
                                    String algorithm, String keyAlgorithm,
                                    byte[] ivArr) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithm);
        SecretKeySpec key = new SecretKeySpec(keyArr, keyAlgorithm);
        IvParameterSpec iv = new IvParameterSpec(ivArr);
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(dataArr);
    }

    /**
     * MD5加密
     *
     * @param data
     * @return 加密后字符串
     */
    public static String md5(String data) {
        String hash = "";
        String algorithm = "MD5";
        try {
            MessageDigest md = MessageDigest.getInstance(algorithm);
            md.update(data.getBytes(DEFAULT_CHARSET));
            byte[] digest = md.digest();
            hash = AlgorithmHelper.byteArrayToHexString(digest);
        } catch (Exception e) {
            log.error("Error {}", algorithm, e);
        }
        return hash;
    }

    /**
     * sha1加密
     *
     * @param data 数据
     * @return 加密后字符串
     */
    public static String sha1(String data) {
        String hash = "";
        String algorithm = "SHA1";
        try {
            MessageDigest md = MessageDigest.getInstance(algorithm);
            md.update(data.getBytes(DEFAULT_CHARSET));
            byte[] digest = md.digest();
            hash = AlgorithmHelper.byteArrayToHexString(digest);
        } catch (Exception e) {
            log.error("Error {}", algorithm, e);
        }
        return hash;
    }

    /**
     * sha256_HMAC加密
     *
     * @param data   数据
     * @param secret 秘钥
     * @return 加密后字符串
     */
    public static String sha256_HMAC(String data, String secret) {
        String hash = "";
        String algorithm = "HmacSHA256";
        try {
            Mac sha256_HMAC = Mac.getInstance(algorithm);
            Key key = new SecretKeySpec(secret.getBytes(DEFAULT_CHARSET), algorithm);
            sha256_HMAC.init(key);
            byte[] bytes = sha256_HMAC.doFinal(data.getBytes(DEFAULT_CHARSET));
            hash = AlgorithmHelper.byteArrayToHexString(bytes);
        } catch (Exception e) {
            log.error("Error {}", algorithm, e);
        }
        return hash;
    }

}
